package com.writing.service.impl;

import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.writing.controller.VoiceGenerationController.VoiceGenerationRequest;
import com.writing.controller.VoiceGenerationController.VoiceGenerationResponse;
import com.writing.controller.VoiceGenerationController.VoiceData;
import com.writing.entity.ApiConfig;
import com.writing.service.ApiConfigService;
import com.writing.service.VoiceGenerationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.List;

/**
 * 语音合成服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VoiceGenerationServiceImpl implements VoiceGenerationService {

    private final ApiConfigService apiConfigService;

    @Value("${dashscope.voice.api-key}")
    private String defaultApiKey;

    @Value("${dashscope.voice.default-voice:}")
    private String defaultVoice;

    @Override
    public VoiceGenerationResponse generateVoice(VoiceGenerationRequest request, Long userId) {
        SpeechSynthesizer synthesizer = null;
        try {
            // 获取API Key：优先使用配置文件中的默认值，如果没有则使用数据库配置
            String apiKey = null;
            
            // 优先使用配置文件中的API Key
            if (defaultApiKey != null && !defaultApiKey.trim().isEmpty()) {
                apiKey = defaultApiKey.trim();
                log.info("使用配置文件中的API Key");
            } else {
                // 如果配置文件中没有，则尝试从数据库获取
                List<ApiConfig> configs = apiConfigService.getEnabledConfigs();
                if (configs != null && !configs.isEmpty()) {
                    ApiConfig config = configs.get(0);
                    apiKey = config.getApiKey();
                    log.info("使用数据库中的API配置");
                }
            }
            
            if (apiKey == null || apiKey.trim().isEmpty()) {
                throw new RuntimeException("未找到可用的API Key配置");
            }

            // 验证SSML模式
            if (request.getUseSSML() != null && request.getUseSSML()) {
                if (!"cosyvoice-v2".equals(request.getModel())) {
                    throw new RuntimeException("SSML模式仅支持cosyvoice-v2模型，当前模型: " + request.getModel());
                }
                // 检查文本是否包含speak标签（可选检查，SDK会自动处理）
                String text = request.getText();
                if (text != null && !text.trim().isEmpty()) {
                    if (!text.contains("<speak>") && !text.contains("</speak>")) {
                        log.warn("SSML模式启用，但文本中未找到<speak>标签，建议将文本包裹在<speak></speak>标签内");
                    }
                }
                log.info("使用SSML模式进行语音合成");
            }

            // 构建语音合成参数（参考官方示例）
            // 音色优先级：请求中的音色 > 配置文件中的默认音色 > 模型默认音色
            SpeechSynthesisParam param;
            String voice = null;
            
            // 优先使用请求中的音色
            if (request.getVoice() != null && !request.getVoice().trim().isEmpty()) {
                voice = request.getVoice().trim();
                log.info("使用请求中的音色: {}", voice);
            } else if (defaultVoice != null && !defaultVoice.trim().isEmpty()) {
                // 如果请求中没有音色，使用配置文件中的默认音色
                voice = defaultVoice.trim();
                log.info("使用配置文件中的默认音色: {}", voice);
            }
            
            // 构建参数
            if (voice != null && !voice.isEmpty()) {
                param = SpeechSynthesisParam.builder()
                        .apiKey(apiKey)
                        .model(request.getModel())
                        .voice(voice)
                        .build();
            } else {
                // 如果都没有，使用模型默认音色
                param = SpeechSynthesisParam.builder()
                        .apiKey(apiKey)
                        .model(request.getModel())
                        .build();
                log.info("使用模型默认音色");
            }

            // 注意：format 和 sampleRate 参数可能需要通过其他方式设置
            // 或者由SDK根据模型自动选择，这里先使用基本参数
            log.info("音频格式: {}, 采样率: {}Hz (如果SDK支持)", request.getFormat(), request.getSampleRate());

            log.info("调用语音合成API，模型: {}, 文本长度: {}, 格式: {}, 采样率: {}Hz", 
                    request.getModel(), request.getText().length(), request.getFormat(), request.getSampleRate());

            // 创建语音合成器（同步模式：禁用回调，第二个参数为null）
            synthesizer = new SpeechSynthesizer(param, null);

            // 调用语音合成接口，阻塞直至音频返回
            ByteBuffer audioBuffer;
            try {
                audioBuffer = synthesizer.call(request.getText());
            } catch (Exception e) {
                // 获取请求ID用于错误追踪
                String requestId = synthesizer.getLastRequestId();
                log.error("语音合成调用失败，请求ID: {}", requestId, e);
                throw new RuntimeException("语音合成API调用失败: " + e.getMessage() + (requestId != null ? " (请求ID: " + requestId + ")" : ""), e);
            }

            // 获取请求ID和首包延迟（如果可用）
            String requestId = synthesizer.getLastRequestId();
            Long firstPackageDelay = synthesizer.getFirstPackageDelay();
            if (requestId != null) {
                log.info("语音合成请求ID: {}, 首包延迟: {}ms", requestId, firstPackageDelay);
            }

            // 检查音频数据是否为空（API可能返回错误但call方法仍返回null）
            if (audioBuffer == null) {
                String errorMsg = "语音合成失败：未返回音频数据，可能是API权限不足或API Key无效";
                if (requestId != null) {
                    errorMsg += "，请求ID: " + requestId;
                }
                errorMsg += "。请检查API Key是否正确，以及是否有权限访问该模型。";
                log.error(errorMsg);
                throw new RuntimeException(errorMsg);
            }

            // 将音频数据转换为Base64
            byte[] audioBytes = new byte[audioBuffer.remaining()];
            audioBuffer.get(audioBytes);
            String base64Audio = Base64.getEncoder().encodeToString(audioBytes);
            
            log.info("语音合成成功，音频数据大小: {} 字节", audioBytes.length);

            // 构建响应
            VoiceGenerationResponse result = new VoiceGenerationResponse();
            VoiceData voiceData = new VoiceData();
            voiceData.setB64Json(base64Audio);
            
            // 计算音频时长（估算，基于采样率和数据大小）
            // 注意：这里只是估算，实际时长应该从API响应中获取
            // 但DashScope SDK的同步调用可能不直接提供时长信息
            // 可以尝试从requestId或其他方式获取，这里暂时不设置
            
            result.setData(voiceData);
            return result;

        } catch (Exception e) {
            log.error("语音合成失败", e);
            throw new RuntimeException("语音合成失败: " + e.getMessage(), e);
        } finally {
            // 任务结束关闭websocket连接
            if (synthesizer != null && synthesizer.getDuplexApi() != null) {
                try {
                    synthesizer.getDuplexApi().close(1000, "bye");
                } catch (Exception e) {
                    log.warn("关闭WebSocket连接失败", e);
                }
            }
        }
    }
}

